import time
from threading import Lock
from typing import Dict, Any


class UARTDataParser:
    def __init__(self):
        # 数据锁
        self.data_lock = Lock()

        # 摇杆数据
        self.rocker_data = {
            'frame_num': 0,
            'rocker1': 0,  # X轴
            'rocker2': 0,  # Y轴
            'last_rocker_num': 255,
            'now_rocker_num': 0,
            'rocker_err': 0,
            'wait_rocker_stable_num': -1
        }

        # 按键数据
        self.key_data = {
            'frame_num': 0,
            'key_status': 0,
            'last_aj_num': 255,
            'now_aj_num': 0,
            'aj_err': 0,
            'wait_aj_stable_num': -1
        }

        # 数据回调
        self.data_callbacks = {
            'on_rocker_data': None,
            'on_key_data': None,
            'on_frame_error': None
        }

        # 原始数据记录
        self.raw_data_log = []
        self.max_log_count = 50

    def set_data_callbacks(self, on_rocker_data=None, on_key_data=None, on_frame_error=None):
        """设置数据回调函数"""
        self.data_callbacks = {
            'on_rocker_data': on_rocker_data,
            'on_key_data': on_key_data,
            'on_frame_error': on_frame_error
        }

    def on_data_notify(self, data: bytes):
        """处理UART数据通知 - 对应Android的OnDataNotify方法"""
        if not data or len(data) == 0:
            return  # 空数据直接返回

        # 检查帧头
        if not self._check_frame_header(data):
            print(f"⚠️ 无效帧头，数据被忽略: {data.hex()}")
            return

        data_len = len(data)

        with self.data_lock:
            if data_len == 9:
                self._parse_rocker_data(data)
            elif data_len == 7:
                self._parse_key_data(data)
            else:
                print(f"⚠️ 未知数据长度: {data_len}, 数据: {data.hex()}")

            # 记录原始数据
            self._log_raw_data(data)

    def _check_frame_header(self, data: bytes) -> bool:
        """检查帧头和帧尾有效性 - 支持多种格式"""
        if len(data) < 4:  # 至少需要帧头2字节+帧尾2字节
            return False

        # 检查两种帧头帧尾格式：
        # 格式1: 摇杆数据 - 帧头 5A5B, 帧尾 B5A5
        # 格式2: 按键数据 - 帧头 AA55, 帧尾 55AA
        format1_ok = (data[0] == 0x5A and data[1] == 0x5B and
                      data[-2] == 0xB5 and data[-1] == 0xA5)

        format2_ok = (data[0] == 0xAA and data[1] == 0x55 and
                      data[-2] == 0x55 and data[-1] == 0xAA)

        return format1_ok or format2_ok

    def _get_frame_type(self, data: bytes) -> str:
        """获取帧类型"""
        if data[0] == 0x5A and data[1] == 0x5B:
            return "rocker"
        elif data[0] == 0xAA and data[1] == 0x55:
            return "key"
        else:
            return "unknown"

    def _parse_rocker_data(self, data: bytes):
        """解析摇杆数据 - 9字节"""
        if len(data) != 9:
            print(f"❌ 摇杆数据长度错误: {len(data)} != 9")
            return

        try:
            # 解析数据 - 跳过帧头(2字节)和帧尾(2字节)
            # 数据格式: [5A, 5B, frame_num, data3, data4, data5, data6, B5, A5]
            frame_num = data[2] & 0xFF

            # 摇杆数据在字节3-6
            rocker1 = (data[4] << 8) | (data[3] & 0xFF)
            rocker2 = (data[6] << 8) | (data[5] & 0xFF)

            # 处理有符号数（Java的short是有符号的）
            rocker1 = self._to_signed_short(rocker1)
            rocker2 = self._to_signed_short(rocker2)

            # 更新摇杆数据
            self.rocker_data.update({
                'frame_num': frame_num,
                'rocker1': rocker1,
                'rocker2': rocker2,
                'now_rocker_num': frame_num
            })

            # 帧号连续性检查
            self._check_rocker_frame_continuity()

            # 触发回调
            if self.data_callbacks['on_rocker_data']:
                self.data_callbacks['on_rocker_data'](frame_num, rocker1, rocker2)

            # 打印解析结果
            # print(f"🎮 摇杆数据: 帧号={frame_num}, X={rocker1}, Y={rocker2}")

        except Exception as e:
            print(f"❌ 解析摇杆数据错误: {e}, 数据: {data.hex()}")


    def _parse_key_data(self, data: bytes):
        """解析按键数据 - 7字节"""
        if len(data) != 7:
            print(f"❌ 按键数据长度错误: {len(data)} != 7")
            return

        try:
            # 解析数据 - 数据格式: [5A, 5B, frame_num, data3, key_status, B5, A5]
            frame_num = data[2] & 0xFF
            key_status = data[4] & 0xFF  # 按键状态在字节4

            # 更新按键数据
            self.key_data.update({
                'frame_num': frame_num,
                'key_status': key_status,
                'now_aj_num': frame_num
            })

            # 帧号连续性检查
            self._check_key_frame_continuity()

            # 触发回调
            if self.data_callbacks['on_key_data']:
                self.data_callbacks['on_key_data'](frame_num, key_status)

            # 打印解析结果和按键详情
            self._print_key_details(key_status, frame_num)

        except Exception as e:
            print(f"❌ 解析按键数据错误: {e}, 数据: {data.hex()}")

    def _to_signed_short(self, value: int) -> int:
        """将16位无符号数转换为有符号short"""
        if value > 32767:
            return value - 65536
        return value

    def _print_key_details(self, key_status: int, frame_num: int):
        """打印按键详情"""
        print(f"  按键状态: {key_status}")

    def on_data_notify(self, data: bytes):
        """处理UART数据通知 - 改进版本"""
        if not data or len(data) == 0:
            return

        # 调试信息
        data_len = len(data)
        hex_data = data.hex()
        print(f"📥 收到数据: 长度={data_len}, 数据={hex_data}")

        # 检查帧头和帧尾
        if not self._check_frame_header(data):
            print(f"⚠️ 无效帧头帧尾，数据被忽略")
            return

        frame_type = self._get_frame_type(data)

        with self.data_lock:
            if frame_type == "rocker" and data_len == 9:
                # print("🔍 识别为摇杆数据(5A5B帧头)")
                self._parse_rocker_data(data)
            elif frame_type == "key" and data_len == 7:
                # print("🔍 识别为按键数据(AA55帧头)")
                self._parse_key_data(data)
            else:
                print(f"⚠️ 未知数据格式: 类型={frame_type}, 长度={data_len}")

            # 记录原始数据
            self._log_raw_data(data)

    def _check_rocker_frame_continuity(self):
        """检查摇杆帧号连续性"""
        last_num = self.rocker_data['last_rocker_num']
        now_num = self.rocker_data['now_rocker_num']
        wait_stable = self.rocker_data['wait_rocker_stable_num']

        if wait_stable >= 0:
            if last_num != 255:
                if (last_num + 1) % 256 != now_num:
                    self.rocker_data['rocker_err'] += 1
            else:
                if (last_num - 254) % 256 != now_num:
                    self.rocker_data['rocker_err'] += 1
        else:
            self.rocker_data['wait_rocker_stable_num'] += 1

        # 更新帧号
        self.rocker_data['last_rocker_num'] = now_num

        # 触发错误回调
        if self.data_callbacks['on_frame_error']:
            self.data_callbacks['on_frame_error']('rocker',
                                                  self.rocker_data['rocker_err'], last_num, now_num)

    def _check_key_frame_continuity(self):
        """检查按键帧号连续性"""
        last_num = self.key_data['last_aj_num']
        now_num = self.key_data['now_aj_num']
        wait_stable = self.key_data['wait_aj_stable_num']

        if wait_stable >= 0:
            if last_num != 255:
                if (last_num + 1) % 256 != now_num:
                    self.key_data['aj_err'] += 1
            else:
                if (last_num - 254) % 256 != now_num:
                    self.key_data['aj_err'] += 1
        else:
            self.key_data['wait_aj_stable_num'] += 1

        # 更新帧号
        self.key_data['last_aj_num'] = now_num

        # 触发错误回调
        if self.data_callbacks['on_frame_error']:
            self.data_callbacks['on_frame_error']('key',
                                                  self.key_data['aj_err'], last_num, now_num)

    def _log_raw_data(self, data: bytes):
        """记录原始数据"""
        timestamp = time.strftime("%H:%M:%S")
        hex_data = data.hex()

        self.raw_data_log.append((timestamp, hex_data, len(data)))

        # 限制日志数量
        if len(self.raw_data_log) > self.max_log_count:
            self.raw_data_log = self.raw_data_log[-self.max_log_count:]

    def get_rocker_data(self) -> Dict[str, Any]:
        """获取当前摇杆数据"""
        with self.data_lock:
            return self.rocker_data.copy()

    def get_key_data(self) -> Dict[str, Any]:
        """获取当前按键数据"""
        with self.data_lock:
            return self.key_data.copy()

    def get_raw_data_log(self, count: int = 10) -> list:
        """获取原始数据日志"""
        with self.data_lock:
            return self.raw_data_log[-count:]

    def reset_errors(self):
        """重置错误计数"""
        with self.data_lock:
            self.rocker_data.update({
                'rocker_err': 0,
                'wait_rocker_stable_num': -1
            })
            self.key_data.update({
                'aj_err': 0,
                'wait_aj_stable_num': -1
            })
        print("✅ 错误计数已重置")
